package qc.module.platform.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.exception.QCPromptException;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.module.platform.dto.api.APIDto;
import qc.module.platform.dto.api.APIQueryConditionDto;
import qc.module.platform.dto.api.APITreeDto;
import qc.module.platform.entity.QcApis;
import qc.module.platform.mapper.ApiMapper;
import qc.module.platform.repository.QcApiRepository;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Api接口Service
 *
 * @author QuCheng Tech
 * @create 2024/5/6
 */
@Service
public class ApiService {
    
    private QcApiRepository repository;

    @Autowired
    public void setRepository(QcApiRepository repository) {
        this.repository = repository;
    }

    /**
     * 查询API接口信息
     * 
     * @param condition 查询条件
     * @return List<APIDto>
     * @author QcCheng Tech
     * @since 2024/5/6
     */
    public List<APIDto> query(APIQueryConditionDto condition){
        //1.构造查询条件
        LambdaQueryWrapper<QcApis> wrapper = new LambdaQueryWrapper<>();
        if (condition != null){
            if (StringUtils.isNotBlank(condition.getKeywords())){
                wrapper.and(q -> q.like(QcApis::getId,condition.getKeywords()).or()
                        .like(QcApis::getUrl,condition.getKeywords()).or()
                        .like(QcApis::getMethod,condition.getKeywords()).or()
                        .like(QcApis::getName,condition.getKeywords()).or()
                        .like(QcApis::getApigroup,condition.getKeywords()).or()
                        .like(QcApis::getDescription,condition.getKeywords()));
            }
        }
        
        //2.排序
        wrapper.orderByAsc(QcApis::getApigroup);
        wrapper.orderByAsc(QcApis::getId);
        //wrapper.groupBy(QcApis::getApigroup);//使用groupby报错 https://zhuanlan.zhihu.com/p/181278176
        
        //3.查询数据
        List<QcApis> ens = repository.selectList(wrapper);
        
        //4.如果有数据记录，enList转换为dtoList返回
        if (ens.size() > 0x0)
            return ApiMapper.MAPPER.toDtoList(ens);
        return null;
    }

    /**
     * 查询API树型信息
     * 父级为分组，子级为api信息
     *
     * @param condition 查询条件
     * @return List<APIDto>
     * @author QcCheng Tech
     * @since 2024/5/10
     */
    public List<APITreeDto> queryTree(APIQueryConditionDto condition) throws QCPromptException {
        List<APITreeDto> result = new ArrayList<>();
        
        if (condition == null) throw new QCPromptException("查询条件对象为空");

        //查询所有API
        List<APIDto> apiDtoList = query(condition);
        //查询所有分组
        List<String> groups = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(apiDtoList)){
            //List<String> groupList = apiDtoList.stream().map(map -> map.getApigroup()).collect(Collectors.toList());
            List<String> groupList = new ArrayList<>();
            for (APIDto apiDto : apiDtoList){
                if (StringUtils.isNotBlank(apiDto.getApigroup())){
                   groupList.add(apiDto.getApigroup()); 
                }else {
                    groupList.add("未分组");
                    apiDto.setApigroup("未分组");
                }
            }
            groups = groupList.stream().distinct().collect(Collectors.toList());//去重
        }
        
        //分组作为父节点,分组的api作为子节点
        if (CollectionUtils.isNotEmpty(groups)){
            for (String group : groups){
                APITreeDto apiTreeDto = new APITreeDto();
                APIDto info = new APIDto();
                List<APIDto> childs = new ArrayList<>();
                info.setApigroup(group);
                
                
                //找出当前分组的api为子节点
                if (CollectionUtils.isNotEmpty(apiDtoList)){
                    for (APIDto apiDto : apiDtoList){
                        if (apiDto.getApigroup().equals(group)){
                            APIDto child = apiDto;
                            childs.add(child);
                        }
                    }
                }
                apiTreeDto.setInfo(info);
                ////结果按照id升序
                apiTreeDto.setChilds(childs.stream().sorted(Comparator.comparing(APIDto::getId)).collect(Collectors.toList()));
                result.add(apiTreeDto);
            }
        }
        
        return result;
    }

    /**
     * 获取指定API信息
     * 
     * @param id 唯一标识
     * @return APIDto
     * @author QuCheng Tech
     * @since 2024/5/6
     */
    public APIDto get(String id){
        QcApis en = repository.selectById(id);
        
        if (Objects.nonNull(en)){
            return ApiMapper.MAPPER.toDto(en);
        }
        return null;
    }

    /**
     * 新增
     * 
     * @param dto 新增dto
     * @return 成功返回null，失败返回错误或提示信息
     * @author QuCheng Tech
     * @since 2024/5/6
     */
    public String add(APIDto dto){
        //1.新增对象判空
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("新增对象不能为空");
        if (StringUtils.isBlank(dto.getId())) return QCUnifyReturnValue.Warn("ID不能为空");
        if (StringUtils.isBlank(dto.getUrl())) return QCUnifyReturnValue.Warn("接口路径不能为空");
        if (dto.getMethod() == null) return QCUnifyReturnValue.Warn("请求方法不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("接口名称不能为空");
        
        //2.唯一标识不能重复
        if (isExist(dto.getId())) return QCUnifyReturnValue.Warn("新增对象已经存在");
        
        //3.同一分组下接口路径不能重复
        if(urlisExist(dto.getId(),dto.getApigroup(),dto.getUrl())) 
            return QCUnifyReturnValue.Warn("同一分组下url不能重复");
        
        //4.dto -> entity
        QcApis en = ApiMapper.MAPPER.dtoToEntity(dto);

        //5.保存数据
        if (repository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("新增数据失败");
        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改
     * 
     * @param dto 修改Dto
     * @return 成功返回null，失败返回错误或提示信息
     * @author QuCheng Tech
     * @since 2024/5/7
     */
    public String update(APIDto dto){
        //1.修改对象判空
        if (Objects.isNull(dto)) return QCUnifyReturnValue.Warn("修改对象不能为空");
        if (StringUtils.isBlank(dto.getId())) return QCUnifyReturnValue.Warn("ID不能为空");
        if (StringUtils.isBlank(dto.getUrl())) return QCUnifyReturnValue.Warn("接口路径不能为空");
        if (dto.getMethod() == null) return QCUnifyReturnValue.Warn("请求方法不能为空");
        if (StringUtils.isBlank(dto.getName())) return QCUnifyReturnValue.Warn("接口名称不能为空");

        //2.唯一标识是否存在
        if (!isExist(dto.getId())) return QCUnifyReturnValue.Warn("修改对象不存在或已删除");

        //3.同一分组下接口路径不能重复
        if(urlisExist(dto.getId(),dto.getApigroup(),dto.getUrl()))
            return QCUnifyReturnValue.Warn("同一分组下url不能重复");
        
        //4.dto -> entity
        QcApis en = ApiMapper.MAPPER.dtoToEntity(dto);
        
        //5.修改数据
        repository.updateById(en);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除
     * 
     * @param id ID
     * @return 成功返回null，失败返回错误或提示信息
     * @author QuCheng Tech
     * @since 2024/5/7
     */
    public String delete(String id){
        repository.deleteById(id);
        return QCUnifyReturnValue.Success();
    }

    /**
     * 导入api
     *
     * @param dtoList 导入的对象集合
     * @return 成功返回null，失败返回错误或提示信息
     * @author QuCheng Tech
     * @since 2024/5/7
     */
    public String importApi(List<APIDto> dtoList){
        //1.判空
        if (CollectionUtils.isEmpty(dtoList)) return QCUnifyReturnValue.Warn("导入数据不能为空");
        
        //2.成功导入successCount条数据，失败导入failCount条数据,已存在isExistCount条数据。
        int successCount = 0x0;
        int failCount = 0x0;
        int isExistCount = 0x0;
        
        //3.dtoList转换为entityList
        List<QcApis> ens = ApiMapper.MAPPER.toEntityList(dtoList);
        
        //4.保存数据，数据不存在才导入
        for (QcApis api : ens){
            if (!isExist(api.getId())){
                if (repository.insert(api) < 0x1){
                    failCount ++;
                }else {
                    successCount ++;
                } 
            }else {
                isExistCount ++;
            }
        }
        
        return QCUnifyReturnValue.Success("导入成功" + successCount + "条数据，导入失败" + 
                failCount + "条数据，已存在" + isExistCount + "条数据。");
    }

    /**
     * 判断ID是否存在
     * @param id
     * @return 返回true表示存在，false表示不存在
     * @author QuCheng Tech
     * @since 2024/5/6
     */
    public boolean isExist(String id){
        if (Objects.nonNull(repository.selectById(id)))
            return true;
        return false;
    }

    /**
     * 判断url是否存在
     * 同一分组下不重复
     *
     * @param id
     * @param url
     * @return 返回true表示存在，false表示不存在
     * @author QuCheng Tech
     * @since 2024/4/30
     */
    private boolean urlisExist(String id,String group,String url){
        if (StringUtils.isNotBlank(id) && StringUtils.isNotBlank(url)){
            LambdaQueryWrapper<QcApis> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(QcApis::getApigroup,group);
            wrapper.eq(QcApis::getUrl,url);
            wrapper.ne(QcApis::getId,id);
            QcApis en = repository.selectOne(wrapper);
            if (Objects.nonNull(en)) return true;
        }
        return false;
    }
}
